package com.hnblc.blcwms.odata.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.hnblc.blcwms.common.interaction.Response;
import com.hnblc.blcwms.persistent.business.basedefine.entity.Article;
import com.hnblc.blcwms.persistent.business.basedefine.entity.Shipper;
import com.hnblc.blcwms.persistent.business.odata.entity.OdataExpD;
import com.hnblc.blcwms.persistent.business.odata.entity.OdataExpM;
import com.hnblc.blcwms.persistent.business.odata.service.IOdataExpDService;
import com.hnblc.blcwms.persistent.business.odata.service.IOdataExpMService;
import com.hnblc.blcwms.persistent.business.odata.vo.TraceInfo;
import com.hnblc.blcwms.persistent.interfaces.client.entity.ClientAuth;
import com.hnblc.blcwms.persistent.interfaces.sysConfig.service.IFieldDictionaryService;
import com.hnblc.blcwms.serviceapi.api.dto.ration.note.ExpressBody;
import com.hnblc.blcwms.serviceapi.api.dto.ration.note.ExpressHead;
import com.hnblc.blcwms.serviceapi.api.enums.result.businiss.RationNoteResultEnum;
import com.hnblc.blcwms.serviceapi.definition.IBaseDefineService;
import com.hnblc.blcwms.serviceapi.definition.constant.BaseDefineConst;
import com.hnblc.blcwms.serviceapi.odata.IExpressService;
import com.hnblc.blcwms.serviceapi.odata.constant.ExpressConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ExpressService implements IExpressService {


    @Autowired
    IOdataExpDService odataExpDService;

    @Autowired
    IOdataExpMService odataExpMService;

    @Autowired
    IBaseDefineService baseDefineService;


    @Autowired
    IFieldDictionaryService fieldDictionaryService;



    @Override
    public boolean cancelExpress(OdataExpM odataExpM){
        String expStatus  = odataExpM.getStatus();
        if (ExpressConst.ODATA_EXP_M__STATUS__READY.equalsIgnoreCase(expStatus)){

            odataExpM.setStatus(ExpressConst.ODATA_EXP_M__STATUS__CANCELED);
            this.odataExpMService.updateById(odataExpM);

            Map<String,String> conditionMap = new HashMap<>();
            conditionMap.put("enterprise_no",odataExpM.getEnterpriseNo());
            conditionMap.put("warehouse_no",odataExpM.getWarehouseNo());
            conditionMap.put("owner_no",odataExpM.getOwnerNo());
            conditionMap.put("exp_no",odataExpM.getExpNo());
            this.odataExpDService.update(null,new UpdateWrapper<OdataExpD>().allEq(conditionMap)
            .set("status",ExpressConst.ODATA_EXP_M__STATUS__CANCELED));
            return true;
        }else if (ExpressConst.ODATA_EXP_M__STATUS__LOCATED.equalsIgnoreCase(expStatus)||
        ExpressConst.ODATA_EXP_M__STATUS__ONBOARD.equalsIgnoreCase(expStatus)) {
            //TODO 已定位或者组板状态订单暂不取消，因为涉及到查找包裹，所以人工取消
            return false;
        }else return false;
    }

    @Override
    public Response<Boolean> createExpress(ExpressHead expressHead, ClientAuth clientAuth) {
        //传递数据
        OdataExpM odataExpM = buildNewExpressM(expressHead,clientAuth);

        //检查订单是否已存在
        List<OdataExpM> existExp  =   this.odataExpMService.list(new QueryWrapper<OdataExpM>().eq("sourceexp_no",expressHead.getSourceExpNo())
                .eq("cust_no",clientAuth.getCustomNo()));
        if (existExp.size()>0)
            return new Response<>(RationNoteResultEnum.ERROR_EXISTED);
        //判断出货类型是否正确
        String expressType = ExpressConst.EXP_TYPE_CODE_MAP.get(expressHead.getExpType());
        if(expressType==null){
            return new Response<>(RationNoteResultEnum.ERROR_UNKNOWN_TYPE);
        }else {
            odataExpM.setExpType(expressType);
        }
        //验证承运商是否存在，并加载
        Shipper shipper = baseDefineService.getShipperCashe(clientAuth.getWarehouseNo(),expressHead.getLogisticNo());
        if (shipper==null)
            return new Response<>(RationNoteResultEnum.ERROR_UNKNOWN_SHIPPER);
        else{
            if (BaseDefineConst.SHIPPER_ENABLE_QRCODE.equals(shipper.getEnableQrcode())){
                odataExpM.setStatus(ExpressConst.ODATA_EXP_M__STATUS__UNREADY);
            }else{
                odataExpM.setStatus(ExpressConst.ODATA_EXP_D__STATUS__READY);
            }
        }

        //查询商品基础资料是否存在,并加载
        Map<String,OdataExpD> baseArticles = new HashMap<>();
        Double allQty = 0.0;
        for (int i=0;i<expressHead.getOrderDetails().size();i++){
            ExpressBody expressBody = expressHead.getOrderDetails().get(i);
            Article article =  baseDefineService.getArticleCache(clientAuth.getOwnerNo(),expressBody.getOwnerArticleNo());
            if (article==null){
                return new Response<Boolean>(RationNoteResultEnum.ERROR_UNKNOWN_SKU,expressBody.getOwnerArticleNo());
            }else if (baseArticles.containsKey(article.getArticleNo())){
                allQty += expressBody.getPlanQty();
                //合并相同内件的数量
                baseArticles.get(article.getArticleNo()).setArticleQty(baseArticles.get(article.getArticleNo()).getArticleQty()+expressBody.getPlanQty());
            }else{
                allQty += expressBody.getPlanQty();
                OdataExpD odataExpD = this.buildNewExpressD(expressBody,clientAuth);
                odataExpD.setArticleNo(article.getArticleNo());
                odataExpD.setRowId(i+1);
                baseArticles.put(article.getArticleNo(),odataExpD);
            }
        }
        //核对包裹详情SKU数量
        if (baseArticles.size()!=expressHead.getSkuCount())
            return new Response<>(RationNoteResultEnum.ERROR_SKU_COUNT);

        //核对包裹商品总数量
        if (expressHead.getGoodCount().doubleValue() != allQty.doubleValue())
            return new Response<>(RationNoteResultEnum.ERROR_GOOD_COUNT);

        String expNo = "";
        String sheetError = "";


        Map<String,Object> procedureMap = new HashMap<String,Object>(){
            private static final long serialVersionUID = -2816157416233431302L;

            {
                this.put("enterpriseNo",clientAuth.getEnterpriseNo());
                this.put("warehouseNo",clientAuth.getWarehouseNo());
                this.put("sheetType","OE");
            }
        };
        //调用存储过程获取单号
        baseDefineService.getSheetNo(procedureMap);
        odataExpM.setExpNo(procedureMap.get("sheetNo").toString());
        baseArticles.values().forEach(item -> item.setExpNo(procedureMap.get("sheetNo").toString()));
        //调用存储过程初始化品项数据回写
        procedureMap.put("expNo",odataExpM.getExpNo());
        procedureMap.put("ownerNo",clientAuth.getOwnerNo());
        baseDefineService.initUpdateSku(procedureMap);
        //调用存储过程初始化状态跟踪
        procedureMap.put("cancelMsg","");
        procedureMap.put("expStatus","00");
        procedureMap.put("opUser","admin_interface");
        baseDefineService.initStatus(procedureMap);
        if (!this.saveExpress(odataExpM,baseArticles.values())){
            return new Response<>(RationNoteResultEnum.ERROR_SAVE_FAIL);
        }else{
            return new Response<>(RationNoteResultEnum.SUCCESS);
        }
    }

    @Override
    public List<TraceInfo> traceExpressGoods(String expNo) {
        return this.odataExpMService.selectTraceInfo(expNo);
    }


    @Transactional
    @Override
    public boolean saveExpress(OdataExpM odataExpM, Collection<OdataExpD> detailList){
        return this.odataExpMService.save(odataExpM)&&this.odataExpDService.saveBatch(detailList);
    }

    /**
     * 构建出货单表头
     * @param expressHead
     * @param clientAuth
     * @return
     */
    private OdataExpM buildNewExpressM(ExpressHead expressHead,ClientAuth clientAuth){
        OdataExpM odataExpM = new OdataExpM();
        odataExpM.setEnterpriseNo(clientAuth.getEnterpriseNo());
        odataExpM.setWarehouseNo(clientAuth.getWarehouseNo());
        odataExpM.setOwnerNo(clientAuth.getOwnerNo());
        odataExpM.setExpType(ExpressConst.EXP_TYPE_CODE_MAP.get(expressHead.getExpType()));
        odataExpM.setOwnerCustNo(clientAuth.getCustomNo());
        odataExpM.setCustNo(clientAuth.getCustomNo());
        odataExpM.setSubCustNo(clientAuth.getCustomNo());
        odataExpM.setSourceexpType(expressHead.getExpType());
        odataExpM.setSourceexpNo(expressHead.getSourceExpNo());
        odataExpM.setFastFlag(expressHead.getFastFlag());
        odataExpM.setCustExpNo(expressHead.getSourceExpNo());
        odataExpM.setShipperDeliverNo(expressHead.getLogisticWaybillNo());
        odataExpM.setShipperNo(expressHead.getLogisticNo());
        odataExpM.setContactorName(expressHead.getReceiver());
        odataExpM.setReceiveTelephone(expressHead.getReceiverMobileNo());
        odataExpM.setReceiveProvince(expressHead.getReceiverProvince());
        odataExpM.setReceiveCity(expressHead.getReceiverCity());
        odataExpM.setReceiveZone(expressHead.getReceiverZone());
        odataExpM.setReceiveCountry(expressHead.getReceiverStreet());
        odataExpM.setSendName(expressHead.getShipper());
        odataExpM.setSendMobilePhone(expressHead.getShipperMobilePhone());
        odataExpM.setSendTelephone(expressHead.getShipperPhoneNo());
        odataExpM.setSendPostcode(expressHead.getShipperPostcode());
        odataExpM.setSendProvince(expressHead.getShipperProvince());
        odataExpM.setSendCity(expressHead.getShipperCity());
        odataExpM.setSendZone(expressHead.getShipperZone());
        odataExpM.setSendCountry(expressHead.getShipperStreet());
        odataExpM.setSendAddress(expressHead.getShipperAddress());
        odataExpM.setDeliverAddress(expressHead.getDeliverAddress());
        odataExpM.setStatus(ExpressConst.ODATA_EXP_M__STATUS__READY);
        odataExpM.setRgstName("admin_interface");
        odataExpM.setRgstDate(LocalDateTime.now());
        odataExpM.setExpStatus(ExpressConst.ODATA_EXP_M__EXP_STATUS__READY);
        return odataExpM;
    }

    /**
     * 构建出货单内件详情
     * @param expressBody
     * @param clientAuth
     * @return
     */
    private OdataExpD buildNewExpressD(ExpressBody expressBody,ClientAuth clientAuth){
        OdataExpD odataExpD = new OdataExpD();
        odataExpD.setWarehouseNo(clientAuth.getWarehouseNo());
        odataExpD.setOwnerNo(clientAuth.getOwnerNo());
        odataExpD.setEnterpriseNo(clientAuth.getEnterpriseNo());
        odataExpD.setOwnerArticleNo(expressBody.getOwnerArticleNo());
        odataExpD.setRgstDate(LocalDateTime.now());
        odataExpD.setPackingQty(expressBody.getPackingQty());
        odataExpD.setArticleQty(expressBody.getPlanQty());
        odataExpD.setUnitCost(expressBody.getUnitCost());
        odataExpD.setStatus(ExpressConst.ODATA_EXP_D__STATUS__READY);
        odataExpD.setExpDate(LocalDateTime.now());
        odataExpD.setRgstDate(LocalDateTime.now());
        odataExpD.setItemType(expressBody.getItemType());
        return odataExpD;
    }



}
